#ifndef ONBOARD_COMPONENT_PERFANP_PERF_COMPONENT_H_
#define ONBOARD_COMPONENT_PERFANP_PERF_COMPONENT_H_

#include <cstdlib>
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include <memory>
#include <map>
#include <mutex>
#include <vector>

#include "chassis.pb.h"
#include "cybertron/cybertron.h"
#include "dv_test_params.pb.h"
#include "latency.pb.h"
#include "noa.pb.h"
#include "perfanp.pb.h"
#include "planning.pb.h"
#include "status_machine.pb.h"
#include "traffic_light_detection.pb.h"

#define CHECK_AND_RETURN(ptr)                   \
    if (ptr == nullptr) {                       \
        LOG_WARN_FORMAT("%s is nullptr", #ptr); \
        return cybertron::FAIL;                 \
    }

#define CHECK_NULL_AND_RETURN(ptr)              \
    if (ptr == nullptr) {                       \
        LOG_WARN_FORMAT("%s is nullptr", #ptr); \
        return;                                 \
    }

#define CHECK_FAIL_AND_RETURN_VALUE(ret, value) \
    if (ret == cybertron::FAIL) {               \
        return value;                           \
    }

#define PERF_CPU ALOG_MODULE("perf_cpu", INFO)

#define PERF_CPU_SLAVE ALOG_MODULE("perf_cpu_slave", INFO)

#define PERF_CPU_H ALOG_MODULE("perf_cpu_thread", INFO)

#define PERF_CPU_SLAVE_H ALOG_MODULE("perf_cpu_slave_thread", INFO)

namespace perfcom {

class PerfComponent : public apollo::cyber::TimerComponent {
 private:
    void stoptop();
    void stopiostat();
    void on_dv_msg_coming(const apollo::dreamview::DVTestParams &msg);
    void on_noamsg_coming(const apollo::noa::NoaMsg &noamsg);
    void on_perf_slave_msg(const std::shared_ptr<const perfanp::Perfmessage> &message);
    void get_version();
    void get_mounted_state();
    void get_software_partnumber();
    void get_dv_compress();
    void get_dv_state();
    std::vector<std::string> split_by_space(const std::string& str);
    void print_gpu_info();
    bool killed = false;
    std::string Trim(std::string str);
    std::shared_ptr<std::thread> cpu_thread = nullptr;
    std::shared_ptr<std::thread> io_thread = nullptr;
    FILE* fp_cpu = nullptr;
    FILE* fp_process = nullptr;
    FILE* fp_cpu_thread = nullptr;
    void get_process_cpu(const std::string& buffer, float& process_cpu);
    int cpu_check_thread();
    FILE* fp_io = nullptr;
    FILE* fp_net = nullptr;
    std::map<std::string, std::map<std::string, float>> _res_net;
    int io_check_thread();
    std::shared_ptr<cybertron::Node> node_;
    std::shared_ptr<cybertron::Reader<apollo::planning::ExecutorInfo>> scene_reader_;
    apollo::executor::ExecutorType executor_type = apollo::executor::ExecutorType::DUMMY_EXECUTOR;
    std::shared_ptr<cybertron::Reader<apollo::status_machine::GlobalState>> statemachine_reader_;

    perfanp::Drivedomain scene_ = perfanp::Drivedomain::URBAN;
    int funcstate_ = static_cast<int>(perfanp::Funcstate::ANP);;
    void get_scene();
    // std::shared_ptr<cybertron::Reader<apollo::chassis::Chassis>> drivemode_reader_;
    perfanp::Drivemode drivemode_ = perfanp::Drivemode::MANU;
    void get_drivemode();
    bool traffic_ = false;
    std::shared_ptr<cybertron::Reader<apollo::patrol::ModuleLatency>> latency_reader_;
    void get_latency(const std::shared_ptr<const apollo::patrol::ModuleLatency>& message);
    perfanp::Perfanp conf;
    perfanp::Perfmessage perfinfo;
    std::shared_ptr<cybertron::Writer<perfanp::Perfmessage>> perf_writer_;
    std::map<std::string, float> process_cpu;
    std::map<std::string, float> process_mem;
    std::map<std::string, uint64_t> module_latency;
    std::map<std::string, float> module_drop_ratio;
    std::map<std::string, uint64_t> module_message_latency;
    std::map<std::string, uint64_t> module_cpu_time;
    float us = 0;
    float sy = 0;
    float ni = 0;
    float id = 0;
    float wa = 0;
    float hi = 0;
    float si = 0;
    float st = 0;
    float anp_master = 0;
    float anp_slave = 0;
    int iops = 0;
    int mem_total = 0;
    int mem_res_used = 0;
    float igpu_util_ = 0;
    float non_sched_cpu = 0;
    bool is_remote_debug = false;
    std::string cpu_info = "\n";
    std::string cpu_info_thread = "\n";
    FILE* fp_metric = nullptr;
    FILE* fp_pidstat_ = nullptr;
    int cs = 0;
    int pgfault = 0;
    int get_sys_metrics(const char* filename, std::string s);
    int cpu_temp_ = 0;
    FILE* fp_temp = nullptr;
    int get_cpu_temp(const char* filename);
    std::mutex info_mutex_;
    std::string version_;
    std::string map_version_;
    std::string task_purpose_;
    std::string task_path_;
    std::string is_mounted_;
    std::string software_partnumber_;
    std::string dv_state_;  // 0: close, 1: open, 2: open but close dv compress
    double longtitude_;
    double latitude_;
    double cpu_slave_{0.0};
    uint32_t mem_slave_{0};
    uint32_t mem_total_slave_{0};
    bool enable_gpu_mem_monitor_{false};
    bool enable_dump_all_bt_{false};
    bool is_orinx_{false};
    float anp_slave_cpu_ = 0;
    bool is_proc_init_ = false;
    std::mutex proc_init_mutex_;

private:
    void ApplicationNotResponse();
    void CheckNotResponse();
    bool ProcInit();

 public:
    PerfComponent();
    ~PerfComponent();
    bool Init() override;
    bool Proc() override;
};

CYBER_REGISTER_COMPONENT(PerfComponent);

}  // namespace perfcom

extern "C" {

int mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp,
    size_t newlen);

}

#endif  //  ONBOARD_COMPONENT_PERFANP_PERF_COMPONENT_H_
